package com.weimengchao.mybatisplus.tool;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @description: 数据对比工具
 * @author: 魏孟超
 * @createDate: 2021-09-26 22:45
 */
public class DataCompare {

    /**
     * @description: 比较list，originalList 获取数据库操作
     * @createAuthor: 魏孟超
     * @createDate: 2021/9/26 22:48
     * @params:
     * @return:
     */
    public <T> DataOperation<T> compare(String primaryKey, List<T> list, List<T> originalList, String... attributeName) throws IllegalAccessException {
        List<String> updateKeys = new ArrayList<>();
        updateKeys.add(primaryKey);
        return compare(updateKeys, list, originalList, attributeName);
    }

    /**
     * @description: 比较list，originalList 获取数据库操作
     * @createAuthor: 魏孟超
     * @createDate: 2021/9/26 22:48
     * @params:
     * @return:
     */
    public <T> DataOperation<T> compare(List<String> updateKeys, List<T> list, List<T> originalList, String... attributeName) throws IllegalAccessException {
        DataOperation<T> dataOperation = new DataOperation<>();
        List<String> onlyList = new ArrayList<>();
        Map<Object, T> newMap = new HashMap<>();
        for (T obj : list) {
            String attributeValue = getAttributeValue(obj, attributeName);
            onlyList.add(attributeValue);
            newMap.put(attributeValue, obj);
        }
        List<String> originalOnlyList = new ArrayList<>();
        Map<Object, T> originalMap = new HashMap<>();
        for (T obj : originalList) {
            String attributeValue = getAttributeValue(obj, attributeName);
            originalOnlyList.add(attributeValue);
            originalMap.put(attributeValue, obj);
        }
        //交集-更新操作
        List<String> updateList = onlyList.stream().filter(o -> originalOnlyList.contains(o))
                .collect(Collectors.toList());
        for (String only : updateList) {
            T t = newMap.get(only);
            T original = originalMap.get(only);
            for (String primaryKey : updateKeys) {
                Object attributeValue = getAttributeValue(original, primaryKey);
                setAttributeValue(t, primaryKey, attributeValue);
            }
            dataOperation.getUpdateList().add(t);
        }
        //新增
        List<String> insertList = onlyList.stream().filter(o -> !originalOnlyList.contains(o))
                .collect(Collectors.toList());
        for (String only : insertList) {
            T t = newMap.get(only);
            dataOperation.getInsertList().add(t);
        }
        //删除
        List<String> deleteList = originalOnlyList.stream().filter(o -> !onlyList.contains(o))
                .collect(Collectors.toList());
        for (String only : deleteList) {
            T t = originalMap.get(only);
            dataOperation.getDeleteList().add(t);
        }
        return dataOperation;
    }

    /**
     * @description: 通过反射设置属性值
     * @createAuthor: 魏孟超
     * @createDate: 2021/9/26 22:49
     * @params:
     * @return:
     */
    public <T> void setAttributeValue(T t, String attributeName, Object attributeValue) throws IllegalAccessException {
        Field[] allFields = getAllFields(t);
        for (int i = 0; i < allFields.length; i++) {
            Field field = allFields[i];
            field.setAccessible(true);
            if (field.getName().equals(attributeName)) {
                field.set(t, attributeValue);
            }
        }
    }

    /**
     * @description: 通过反射过去属性值拼接字符串
     * @createAuthor: 魏孟超
     * @createDate: 2021/9/26 22:50
     * @params:
     * @return:
     */
    public static String getAttributeValue(Object obj, String... attributeNames) throws IllegalAccessException {
        StringBuffer buffer = new StringBuffer();
        for (String attributeName : attributeNames) {
            Object attributeValue = getAttributeValue(obj, attributeName);
            buffer.append(attributeValue);
        }
        return buffer.toString();
    }

    /**
     * @description: 通过反射获取属性值
     * @createAuthor: 魏孟超
     * @createDate: 2021/9/26 22:50
     * @params:
     * @return:
     */
    public static Object getAttributeValue(Object obj, String attributeName) throws IllegalAccessException {
        Field[] fields = getAllFields(obj);
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            field.setAccessible(true);
            String name = field.getName();
            if (attributeName.equals(name)) {
                Object value = field.get(obj);
                if (value == null) {
                    return null;
                }
                return value;
            }
        }
        throw new RuntimeException(attributeName + " 不存在;obj: " + obj);
    }

    /**
     * @description: 通过反射获取字段
     * @createAuthor: 魏孟超
     * @createDate: 2021/9/26 22:50
     * @params:
     * @return:
     */
    public static Field[] getAllFields(Object obj) {
        List<Field> fieldList = new ArrayList<>();
        Class clazz = obj.getClass();
        while (clazz != null) {
            fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            clazz = clazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        return fields;
    }

}
